﻿using Hangfire;
using Hangfire.Dashboard;
using Hangfire.MySql;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
using X23.EFCore;
using X23.Model.Const;
using static X23.Model.Const.Enum;

namespace X23.Extensions
{
    public static class StartupExtensions
    {
        /// <summary>
        /// 注册Swagger
        /// </summary>
        /// <param name="services"></param>
        public static void AddSwagger(this IServiceCollection services)
        {
            //https://github.com/domaindrivendev/Swashbuckle.AspNetCore

            //获取程序集解析程序用于探测程序集的基目录的文件路径。
            var BasePath = AppContext.BaseDirectory;
            services.AddSwaggerGen(c =>
            {
                c.CustomSchemaIds((type) => type.FullName);//命名空间全名称

                c.SwaggerDoc("v1", new OpenApiInfo { Title = "X23", Version = "v1" });

                c.IncludeXmlComments(Path.Combine(BasePath, "Xml", "X23.Model.xml"));
                c.IncludeXmlComments(Path.Combine(BasePath, "Xml", "X23.Application.xml"));
                c.IncludeXmlComments(Path.Combine(BasePath, "Xml", "X23.xml"), true);//默认的第二个参数是false，这个是controller的注释


                #region Token绑定到ConfigureServices
                c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
                {
                    Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}（注意两者之间是一个空格）",
                    Name = "Authorization",//jwt默认的参数名称
                    In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
                    Type = SecuritySchemeType.ApiKey,
                    BearerFormat = "JWT",
                    Scheme = "Bearer"
                });
                c.AddSecurityRequirement(new OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference {
                                Type = ReferenceType.SecurityScheme,
                                Id = "Bearer"
                            }
                        },
                        Array.Empty<string>()
                    }
                });
                #endregion
            });
        }

        /// <summary>
        /// 注册DbContext
        /// </summary>
        /// <param name="services"></param>
        /// <param name="connectionString">连接字符串</param>
        /// <param name="dBType">数据库类型（1mysql 2sqlsever）</param>
        public static void AddDbContext(this IServiceCollection services, string connectionString, DBType dBType = DBType.MySQL)
        {
            if (dBType == DBType.MySQL)
            {
                //https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql
                var serverVersion = new MySqlServerVersion(new Version(8, 0, 27));
                services.AddDbContext<EFCoreContext>(dbContextOptions => dbContextOptions.UseMySql(connectionString, serverVersion));
            }
            else if (dBType == DBType.SQLServer)
            {
                services.AddDbContext<EFCoreContext>(options => options.UseSqlServer(connectionString));
            }
            else
            {
                throw new Exception("只支持mysql和sqlsever数据库！");
            }
        }


        ///// <summary>
        ///// 注册AutoMapper
        ///// </summary>
        ///// <param name="services"></param>
        //public static void AddAutoMapper(this IServiceCollection services)
        //{
        //    services.AddAutoMapper(Assembly.Load("X23.Application"));
        //}

        /// <summary>
        /// 添加Jwt
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        public static void AddJWT(this IServiceCollection services, IConfiguration configuration)
        {
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options => {
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ClockSkew = TimeSpan.FromSeconds(10),//缓冲时间:真正过期时间是 过期时间+缓冲时间
                        ValidateIssuer = true,//是否验证Issuer
                        ValidateAudience = true,//是否验证Audience
                        ValidateLifetime = true,//是否验证失效时间
                        ValidateIssuerSigningKey = true,//是否验证SecurityKey
                        ValidAudience = configuration[AppSettings.JwtAudience],//Audience
                        ValidIssuer = configuration[AppSettings.JwtIssuer],//Issuer，这两项和前面签发jwt的设置一致
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration[AppSettings.JwtSymmetricSecurityKey]))//拿到SecurityKey
                    };

                    options.Events = new JwtBearerEvents
                    {
                        OnMessageReceived = (context) => {

                            if (!context.HttpContext.Request.Path.HasValue)
                            {
                                return Task.CompletedTask;
                            }
                            //重点在于这里；判断是Signalr的路径
                            var accessToken = context.HttpContext.Request.Query["access_token"];
                            var path = context.HttpContext.Request.Path;
                            if (!(string.IsNullOrWhiteSpace(accessToken)) && path.StartsWithSegments("/SignalR"))
                            {
                                context.Token = accessToken;
                                return Task.CompletedTask;
                            }
                            return Task.CompletedTask;
                        }
                    };

                    //options.Events = new JwtBearerEvents
                    //{
                    //    OnChallenge = context =>
                    //    {
                    //        //var jwtHandler = new JwtSecurityTokenHandler();
                    //        //var token = context.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
                    //        //if (string.IsNullOrWhiteSpace(token) && jwtHandler.CanReadToken(token))
                    //        //{
                    //        //    var jwtToken = jwtHandler.ReadJwtToken(token);
                    //        //    if (jwtToken.Issuer != jwt_setting.Issuer)
                    //        //    {
                    //        //        context.Response.Headers.Add("Token-Error-Iss", "issuer is wrong!");
                    //        //    }

                    //        //    if (jwtToken.Audiences.FirstOrDefault() != jwt_setting.Audience)
                    //        //    {
                    //        //        context.Response.Headers.Add("Token-Error-Aud", "Audience is wrong!");
                    //        //    }
                    //        //    var time = jwtToken.ValidTo;
                    //        //    if (time.AddMinutes(5)>DateTimeHelper.DateTimeChineseNow)
                    //        //    {

                    //        //    }
                    //        //}
                    //        context.Response.Headers.Add("Token-Error", context.ErrorDescription);
                    //        return Task.CompletedTask;
                    //    },
                    //};
                });
        }


        //public static void AddX23Hangfire(this IServiceCollection services, string mysqlConnectionString)
        //{
        //    services.AddHangfire(x =>
        //    {
        //        x.UseStorage(new MySqlStorage(
        //            mysqlConnectionString,
        //            new MySqlStorageOptions
        //            {
        //                TransactionIsolationLevel = IsolationLevel.ReadCommitted, // 事务隔离级别。默认是读取已提交。
        //                QueuePollInterval = TimeSpan.FromSeconds(15),             // 作业队列轮询间隔。默认值为15秒。
        //                JobExpirationCheckInterval = TimeSpan.FromHours(1),       // 作业到期检查间隔（管理过期记录）。默认值为1小时。
        //                CountersAggregateInterval = TimeSpan.FromMinutes(5),      // 聚合计数器的间隔。默认为5分钟。
        //                PrepareSchemaIfNecessary = true,                          // 如果设置为true，则创建数据库表。默认是true。
        //                DashboardJobListLimit = 50000,                            // 仪表板作业列表限制。默认值为50000。
        //                TransactionTimeout = TimeSpan.FromMinutes(1),             // 交易超时。默认为1分钟。
        //                //TablesPrefix = "X23"                                      // 数据库中表的前缀。默认为none
        //            }
        //            ));
        //    });
        //    services.AddHangfireServer();
        //}
        
    }
}
